class DryScaffoldController < ApplicationController
  include DryScaffold::Controller

  verify :method => :post, :only => [ :destroy, :create, :update ],
         :redirect_to => { :action => :list }

  # Give your controller a label.
  #
  # This is used in flash messages and in the title of the list.
  def label
    self.controller_name.humanize
  end

  def auto_complete_for_filter_by #:nodoc:
    @find_params = { 
      :order => "#{params[:column]} ASC",
      :limit => 10 }
    build_clause(nil, params[:column], params["#{params[:filter]}"]["#{params[:column]}"].downcase.gsub('_', '\_'), :like => true) 
    @scaffold_model = model_map
    filter_name = "#{like_model_name(@scaffold_model)}"
    eval("@#{filter_name} = #{@scaffold_model}.new()")
    filter_by = eval("@#{filter_name}")
    restrict_to_filter_clause(nil)
    update_find_params_conditions
    @items = params[:model].to_s.camelize.constantize.find(:all, @find_params)
#TODO 2006-09-14 Level=0 - Need to truncate values in the list.
    render :inline => "<%= auto_complete_result @items, '#{params[:column]}' %>"
  end
  
  def index
    list
  end

  def list
  	@list_rows = nil
    list_component
  end
  
  def component
    list_component
  end
  
  def edit
    edit_component
    list_component
  rescue Exception => err
    if ActiveRecord::RecordNotFound === err
      list
    else
      raise err
    end
  end
 
  def new
    new_component
    list_component
  end
   
  def view
    @options ||= params
    one_model = model_map
    if params[:commit] and params[:commit].include?("Reset") and params[:filter_model] == one_model
      list_component
    else
      @options.merge!(:action => 'view')
    	@list_rows = [] # this must be an array
      @one_row ||= one_model.find(params[:id])
      @list_rows << @one_row
      list_component
    end
  rescue Exception => err
    if ActiveRecord::RecordNotFound === err
      list
    else
      raise err
    end
  end

  def show
    show_component
    list_component
  rescue Exception => err
    if ActiveRecord::RecordNotFound === err
      list
    else
      raise err
    end
  end
  
  def create
    update_create(:create)
  end

  def update
    update_create(:update)
  end

  def update_one_field
    one_model, id = one_model_map
    @one_row = one_model.find(id)
    @one_row[params[:field]] = params[:value]
    @one_row.save
    @one_row.reload
    user_key = one_model.user_key    
    if !user_key.nil? and params[:field] == user_key
      html = ''
      if !@one_row[user_key].nil? && !@one_row.user.nil? 
        html << @one_row.user.firstname + " " + @one_row.user.lastname
      end
      render_text html
    else
      render_text @one_row[params[:field]]
    end
  end
  
  def cancel
    one_model, one_id = one_model_map
    child, parent_id = one_child
    sort_sym = sort_limit_field_name(one_model).to_sym
    page_options = { sort_sym => params[sort_sym], :page => params[:page]}
    @one_row = nil
    if child 
      redirect_to page_options.merge(:action => 'view', :model => params[:model], :id => parent_id)
    else 
      redirect_to page_options.merge(:action => 'list', :model => model_map)
    end
  end

  def cancel?
    params[:commit] and params[:commit].include?("Cancel")
  end
  
  def destroy
    one_model, id = one_model_map
    @one_row = one_model.find(id).destroy
    flash.now[:info] = {one_model => "Item " + :deleted.to_s + " from " + one_model.label}
  rescue ActiveRecord::RecordNotFound => e
    flash.now[:notice] = "Unable to remove item from #{one_model.label} because of record does not exist."
  rescue ActiveRecord::StatementInvalid => e
    flash.now[:notice] = "Unable to remove item from #{one_model.label} because of database dependencies."
  ensure
    list_component
  end

  def show_one
    @options ||= params
    @one_row_options ||= {}
    @scaffold_model = model_map
  	@form_options ||= {:action => :list, :model => @scaffold_model}
    @render_params ||= {:template => 'shared/edit_component', :action => '../shared/edit_component'}
    @render_params[:layout] ||= @options[:layout].nil? ? true : @options[:layout]
  	@options.merge!(:model => @scaffold_model, :scaffold_model => @scaffold_model)
    render(@render_params)
  end
    
  def edit_one
    edit_component(:one_only => true)
    show_one
  end
  
  def new_one
    new_component(:one_only => true)
    show_one
  end


  protected

#   def permission_denied
#     flash[:notice] = "You don't have privileges to access this action"
#     redirect_back_or_default :action => 'index'
#   end

#   def permission_granted
#   end

  private

  def list_component(no_limit = false) #:nodoc:
    @options ||= params
    @one_row_options ||= {}
    @scaffold_model = model_map
  	@form_options ||= {:action => :list, :model => @scaffold_model}
    @render_params ||= {:template => 'shared/component', :action => '../shared/component'}
    @render_params[:layout] ||= @options[:layout].nil? ? true : @options[:layout]
  	@options.merge!(:model => @scaffold_model, :scaffold_model => @scaffold_model)
#    logger.debug "xxxxxxxx#{@one_row_options[:crud_model]}xxxxxxx"
    # Discover the heirarchy 
    @pedigree = @options[:pedigree] || []
    u_model = @one_row_options[:crud_model]
    discovering = true
    while discovering
      if u_model.nil?
        discovering = false
      else
        u_model = u_model.to_s.constantize
        @pedigree << [{:model => u_model.to_s.constantize}]
        u_model = u_model.parent_model
      end
    end
    @options[:pedigree] = @pedigree
    if @list_rows.nil?
      # Update here, So that this can overwrite the defaults on the columns
      sort_clause_update(!params[:reset].nil? || !params["reset.x"].nil?) # IE sends reset.x instead of reset
      @find_params ||= {}
      like_clause_update(!params[:reset].nil? || !params["reset.x"].nil?) # IE sends reset.x instead of reset
      @find_params.merge!(:order => sort_clause, :per_page => sort_limit(@scaffold_model)) 
      if @find_params.has_key?(:include_children)
        @list_rows = @scaffold_model.find_by_def @find_params
      elsif params[:parent_id]
      	@form_options.merge!(:action => :view, :id => @options[:parent_id], :model => @options[:parent_model], :filter_model => @scaffold_model)
        if @options[:crud_model].to_s == @scaffold_model.to_s
    			@options[:id] = @options[:crud_id] 
    			@options[:action] = @options[:crud_action]
    			@options[:crud_model] = @options[:crud_model]
    		end
        build_clause @scaffold_model, params[:parent_id_column_name], params[:parent_id].to_s
        update_find_params_conditions
        @paginator, @list_rows = paginate(@scaffold_model.to_s.pluralize, @find_params)
      else
        @paginator, @list_rows = paginate(@scaffold_model.to_s.pluralize, @find_params)
      end
      @paging = true
    end
    render(@render_params)
  end

  def edit_component(options = {}) #:nodoc:
    rescue_action = "edit"
    rescue_action += "_one" unless options[:one_only].nil?
    edit_action = "edit"
    update_action = "update"
    one_model, id = one_model_map
    @one_row_options = {:id => id, :crud_action => edit_action, :rescue_action => rescue_action, :next_action => update_action, :crud_model => one_model}
    @one_row_options[:one_only] = options[:one_only]
    @one_row = flash[:one_row] unless flash[:one_row].nil?
    @one_row ||= one_model.find(params[:id])    
  end

  def new_component(options = {}) #:nodoc:
    rescue_action = "new"
    rescue_action += "_one" unless options[:one_only].nil?
    new_action = "new"
    create_action = "create"
    one_model, id = one_model_map
    @one_row_options = {:id => id, :crud_action => new_action, :rescue_action => rescue_action, :next_action => create_action, :crud_model => one_model}
    @one_row_options[:one_only] = options[:one_only]
    @one_row = flash[:one_row] unless flash[:one_row].nil?
    @one_row ||= one_model.new
  end

  def show_component
    one_model, id = one_model_map
    @one_row_options = {:id => id, :crud_action => 'show', :rescue_action => nil, :next_action => nil, :crud_model => one_model}
    @one_row ||= one_model.find(params[:id])
  end
  
  @child = nil
  def child? #:nodoc:
    @child ||= !params[:parent_model].nil?
  end
  
  @parent_id = nil
  @parent_model = nil
  def one_child #:nodoc:
    if child?
      @parent_id ||= params[:parent_id]
      @parent_model ||= params[:parent_model]
      params[:id] = @parent_id 
      params[:model] = @parent_model
      params.delete(:parent_model)
      params.delete(:parent_id)
    end
    return child?, @parent_id
  end

  def one_model_map #:nodoc:
    if params[:crud_model]
      model = params[:crud_model]
      id = params[:crud_id]
    else
      model = params[:model]
      id = params[:id]
    end
    return model.to_s.camelize.constantize, id
  end

  def update_create(action) #:nodoc:
    @message = ""
    one_model, one_id = one_model_map
    child, parent_id = one_child
    sort_sym = sort_limit_field_name(one_model).to_sym
    page_options = { sort_sym => params[sort_sym], :page => params[:page]}
    if cancel?
      cancel
    else
      case action
        when :update
          @one_row = one_model.find(one_id)
          do_update_before_save one_model
          successful = @one_row.update_attributes(params[:one_row])
          do_update_after_save one_model, successful
          @message << "Item " + :updated.to_s + " in "
        when :create
          eval("params[:one_row][:#{params[:parent_id_column_name]}] ||= parent_id") if child
          @one_row = one_model.new(params[:one_row])
          do_create_before_save one_model
          successful = @one_row.save
#          successful = @one_row.new_record? ? false : true
          do_create_after_save one_model, successful
          @message << "Item " + :created.to_s + " in "
      end
      flash[:one_row] = @one_row unless successful
      flash[:info] = {one_model => @message + one_model.label} if successful
      if (child)
        @one_row = nil
        params.merge!(:crud_action => params[:rescue_action], :rescue_action => params[:rescue_action], :crud_id => one_id, :crud_model => one_model.to_s) unless successful
        if successful
          redirect_to page_options.merge(:action => 'view', :model => params[:model], :id => parent_id)
        else
          view
        end
      else
        if successful 
          redirect_to page_options.merge(:action => 'list', :model => one_model)
        else 
          case action
            when :update
              if params[:one_only] then edit_one else edit end 
            when :create
              if params[:one_only] then new_one else new end
          end
        end
      end    
    end
  end

  # Override this with your application specific code. This method is called on :create after @one_row.new and before @one_row.save.
  def do_create_before_save(one_model)
  end

  # Override this with your application specific code. This method is called on :create after @one_row.save.
  def do_create_after_save(one_model, successful)
  end

  # Override this with your application specific code. This method is called on :create after @one_row.new and before @one_row.save.
  def do_update_before_save(one_model)
  end

  # Override this with your application specific code. This method is called on :create after @one_row.save.
  def do_update_after_save(one_model, successful)
  end
end
